﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text;
using Aliyun.OSS;
using Aliyun.OSS.Common;
using Best.SmartCms.Core.Utility;

namespace Best.SmartCms.Utility
{
    /// <summary>
    /// Oss 服务 上传文件
    /// </summary>
    public class OssService
    {
        private static readonly string Endpoint  = ConfigurationManager.AppSettings["OssEndPoint"];
        private static readonly string AccessKeyId = ConfigurationManager.AppSettings["OssAccessKeyId"];
        private static readonly string AccessKeySecret = ConfigurationManager.AppSettings["OssAccessKeySecret"];
        private static readonly string BucketName = ConfigurationManager.AppSettings["OssBucketName"];
        private static readonly string OssConnectionTimeout = ConfigurationManager.AppSettings["OssConnectionTimeout"];
        private static readonly string OssExpirationTime = ConfigurationManager.AppSettings["OssExpirationTime"];//附件过期时间
        private static OssClient _client;

        public OssService()
        {
            //连接配置
            var conf = new ClientConfiguration
            {
                MaxErrorRetry = 3,
                ConnectionTimeout = int.Parse(OssConnectionTimeout)
            };
            _client = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, conf);
            //公共读权限
            _client.SetBucketAcl(BucketName, CannedAccessControlList.PublicRead);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="formItems"></param>
        /// <param name="cookieContainer"></param>
        /// <param name="refererUrl"></param>
        /// <param name="encoding"></param>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        public string PostForm(string url, List<FormItemModel> formItems, CookieContainer cookieContainer = null, string refererUrl = null, Encoding encoding = null, int timeOut = 20000)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            #region 初始化请求对象  
            request.Method = "POST";
            request.Timeout = timeOut;
            request.Accept = "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            request.KeepAlive = true;
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";
            if (!string.IsNullOrEmpty(refererUrl))
                request.Referer = refererUrl;
            if (cookieContainer != null)
                request.CookieContainer = cookieContainer;
            #endregion

            string boundary = "----" + DateTime.Now.Ticks.ToString("x");//分隔符  
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
            //请求流  
            var postStream = new MemoryStream();
            #region 处理Form表单请求内容  
            //是否用Form上传文件  
            var formUploadFile = formItems != null && formItems.Count > 0;
            if (formUploadFile)
            {
                //文件数据模板  
                string fileFormdataTemplate =
                    "\r\n--" + boundary +
                    "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
                    "\r\nContent-Type: application/octet-stream" +
                    "\r\n\r\n";
                //文本数据模板  
                string dataFormdataTemplate =
                    "\r\n--" + boundary +
                    "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                    "\r\n\r\n{1}";
                foreach (var item in formItems)
                {
                    string formdata;
                    if (item.IsFile)
                    {
                        //上传文件  
                        formdata = string.Format(
                            fileFormdataTemplate,
                            item.Key, //表单键  
                            item.FileName);
                    }
                    else
                    {
                        //上传文本  
                        formdata = string.Format(
                            dataFormdataTemplate,
                            item.Key,
                            item.Value);
                    }

                    //统一处理  
                    byte[] formdataBytes = null;
                    //第一行不需要换行  
                    formdataBytes = Encoding.UTF8.GetBytes(postStream.Length == 0 ? formdata.Substring(2, formdata.Length - 2) : formdata);
                    postStream.Write(formdataBytes, 0, formdataBytes.Length);

                    //写入文件内容  
                    if (item.FileContent != null && item.FileContent.Length > 0)
                    {
                        using (var stream = item.FileContent)
                        {
                            byte[] buffer = new byte[1024];
                            int bytesRead;
                            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                postStream.Write(buffer, 0, bytesRead);
                            }
                        }
                    }
                }

                //结尾  
                var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
                postStream.Write(footer, 0, footer.Length);

            }
            else
            {
                request.ContentType = "application/x-www-form-urlencoded";
            }
            #endregion

            request.ContentLength = postStream.Length;

            #region 输入二进制流  
            {
                postStream.Position = 0;
                //直接写入流  
                Stream requestStream = request.GetRequestStream();

                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    requestStream.Write(buffer, 0, bytesRead);
                }

                postStream.Close();//关闭文件访问  
            }

            #endregion

            var response = (HttpWebResponse)request.GetResponse();
            if (cookieContainer != null)
            {
                response.Cookies = cookieContainer.GetCookies(response.ResponseUri);
            }

            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.UTF8))
                {
                    string retString = myStreamReader.ReadToEnd();
                    return retString;
                }
            }
        }


        /// <summary>
        /// 上传指定的文件到指定的OSS的存储空间
        /// </summary>
        /// <param name="key">文件的在OSS上保存的名称</param>
        /// <param name="fileToUpload">指定上传文件的本地路径</param>
        public  void PutObject( string key, string fileToUpload)
        {
            try
            {
                var result = _client.PutObject(BucketName, key, fileToUpload);
                _client.SetObjectAcl(BucketName, key, CannedAccessControlList.PublicRead);
                NLogManager.LogTrace("Put object succeeded!ETag:{0}", result.ETag);
            }
            catch (Exception ex)
            {
                NLogManager.LogTrace("Put object failed!{0}",ex.Message);
            }
        }

        /// <summary>
        /// 字节流保存
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="objectKey"></param>
        /// <returns></returns>
        public bool SaveFileToOssByBytes(byte[] bytes, string objectKey)
        {
            bool result = false;
            try
            {
                using (Stream fs = new MemoryStream(bytes))
                {
                    var putResult = _client.PutObject(BucketName, objectKey, fs);
                    fs.Flush();
                    fs.Close();
                    if (!string.IsNullOrEmpty(putResult.ETag))
                    {
                        result = true;
                    }
                }

            }
            catch (Exception ex)
            {
                NLogManager.LogError(ex);
                result = false;
            }
            return result;
        }


        /// <summary>
        ///  创建带签名的图片链接
        /// </summary>
        /// <param name="ossKey"></param>
        /// <param name="weight"></param>
        /// <param name="height"></param>
        public  string GenerateIamgeUri(string ossKey,string weight = null ,string height =null)
        {
            if (string.IsNullOrEmpty(ossKey)) return "";
            try
            {
                var process =(weight != null && height != null) ?  $"image/resize,m_fixed,w_{weight},h_{height}" : "image/resize,p_100";
                var req = new GeneratePresignedUriRequest(BucketName, ossKey, SignHttpMethod.Get)
                {
                    Expiration = DateTime.Now.AddSeconds(long.Parse(OssExpirationTime)),
                    Process = process
                };
                // 产生带有签名的URI
                var uri = _client.GeneratePresignedUri(req);
                return uri.ToString();
            }
            catch (Exception ex)
            {
               NLogManager.LogError("创建签名图片链接失败，失败原因："+ex.Message);
                throw new Exception("创建签名图片链接失败，失败原因：" + ex.Message);
            }
        }

        /// <summary>
        /// 从Oss获取文件流
        /// </summary>
        /// <param name="objectKey"></param>
        /// <returns></returns>
        public byte[] GetFileFromOss(string objectKey)
        {
            try
            {
                var obj = _client.GetObject(BucketName, objectKey);

                using (MemoryStream ms = new MemoryStream())
                {
                    byte[] buf = new byte[1024];
                    var len = 0;
                    while ((len = obj.Content.Read(buf, 0, 1024)) != 0)
                    {
                        ms.Write(buf, 0, len);
                    }
                    ms.Close();

                    return ms.ToArray();
                }
            }
            catch (Exception ex)
            {
                NLogManager.LogError(ex);
                return null;
            }
        }
     

    }

    /// <summary>
    /// Form 对象
    /// </summary>
    public class FormItemModel
    {
        /// <summary>  
        /// 表单键，request["key"]  
        /// </summary>  
        public string Key { set; get; }
        /// <summary>  
        /// 表单值,上传文件时忽略，request["key"].value  
        /// </summary>  
        public string Value { set; get; }
        /// <summary>  
        /// 是否是文件  
        /// </summary>  
        public bool IsFile
        {
            get
            {
                if (FileContent == null || FileContent.Length == 0)
                    return false;

                if (FileContent != null && FileContent.Length > 0 && string.IsNullOrWhiteSpace(FileName))
                    throw new Exception("上传文件时 FileName 属性值不能为空");
                return true;
            }
        }
        /// <summary>  
        /// 上传的文件名  
        /// </summary>  
        public string FileName { set; get; }
        /// <summary>  
        /// 上传的文件内容  
        /// </summary>  
        public Stream FileContent { set; get; }
    }

 
}
